
(function (global, TempVue) {
    global.TempVue = TempVue()
})(this, function () {
    // 主体 类 接收参数
    class TempVue {
        constructor(options) {
            this.$options = options;
            this.$data = options.data;
            this.$methods = options.methods;

            //初始化数据调用
            this.observe(this.$data);

            // 将this.$data内的属性代理到this上
            this.proxy(this.$data);
            this.proxy(this.$methods);
            // 模拟Watcher 创建
            // new Watcher()
            // this.$data.a
            // new Watcher()
            // this.$data.b.c
            options.created && options.created.call(this);
            new Compile(options.el, this);
            options.mounted && options.mounted.call(this);
        }
        // 数据初始化函数
        observe(data) {
            // 判断data是否存在 不存在或者不是对象则直接return
            if (!data || typeof data !== 'object') return;

            // 遍历对象
            Object.keys(data).forEach(key => {
                // 通过Object.defineProperty 做数据劫持
                this.defineReactive(data, key, data[key]);
            });

        }

        // 代理函数
        proxy(data = {}) {
            Object.keys(data).forEach(key => {
                let val = data[key]
                Object.defineProperty(this, key, {
                    enumerable: true,
                    configurable: true,
                    set(newVal) {
                        if (newVal === val) return
                        return newVal
                    },
                    get() {
                        return val
                    }
                })
            })
        }
        // 数据响应函数（数据劫持）
        defineReactive(data, key, val) {
            typeof val === 'object' && this.observe(val); // 递归数据嵌套

            const dep = new Dep();

            Object.defineProperty(data, key, {
                get() {
                    // 读取时将watcher的实例 通过addSub添加给依赖列表
                    // console.log(Dep.target, '=====')
                    Dep.target && dep.addSub(Dep.target);
                    // console.log('get', 'push==========' )
                    return val
                },
                set(newValue) {
                    if (val === newValue) return;
                    console.log('set')
                    val = newValue;
                    // 调用通告函数 更新数据
                    dep.notify();
                }
            });
        }
    }

    // Dep: 管理Watcher  这单词啥意思没搞懂就看源码这么写的
    class Dep {
        constructor() {
            // 依赖列表
            this.subs = [];
        }
        // 添加数据依赖
        addSub(sub) {
            console.log('添加了')
            this.subs.push(sub);
        }
        // 调用依赖的upload函数 数据更新
        notify() {
            console.log(this.subs)
            this.subs.forEach(sub => sub.update());
        }
    }

    // Watcher观察数据变化
    class Watcher {
        constructor(vm, callback, key, cb) {
            this.vm = vm;
            this.key = key;
            this.cb = cb;
            this.callback = callback
            // console.log('watcher')
            // 将watcher实例指定到Dep静态属性上
            Dep.target = this;
            // 触发get方法 
            callback(key, this.vm.$data, this.vm.$data)
            Dep.target = null;
        }

        // 更新数据
        update() {
            let val = this.callback(this.key, this.vm.$data, this.vm.$data)
            this.cb.call(this.vm, val);
        }
    }

    // 编译器
    class Compile {
        constructor(el, vm) {
            // 拿到主dom节点
            this.$el = document.querySelector(el);
            // 将TempVue的实例挂载到$vm
            this.$vm = vm;

            //编译
            if (this.$el) {
                // 将dom节点创建成虚拟dom树
                this.$vNode = this.domFragment(this.$el);
                // console.log(this.$vNode)
                // 执行编译
                this.compile(this.$vNode);
                // 将编译完的html结果追加到$el
                // this.$el.appendChild(this.$fragment);
            }
        }
        // 创建dom树
        domFragment(node) {
            // 创建虚拟dom树
            let temp = new VNode(node, node.nodeType, node.nodeValue);
            // 匹配插值语法
            let contentTemplate = temp.isInterpolation(node.nodeValue);
            // 将匹配到的字符串添加到dom树中
            temp.appendContentTemplate(contentTemplate);
            // for (let i = 0; i < node.childNodes.length; i++) {
            //     if (node.childNodes[i].nodeType === 1) {
            //         let child = this.domFragment(node.childNodes[i])
            //         temp.appendChildNode(child)
            //     } else if (node.childNodes[i].nodeType === 3) {
            //         let child = this.domFragment(node.childNodes[i])
            //         temp.appendChildNode(child);
            //     } else {
            //         continue
            //     }
            // }
            // 遍历node的childNodes

            let childArr = Array.prototype.slice.call(node.childNodes, 0);

            // 遍历dom节点
            childArr.forEach(item => {
                if (this.isElement(item)) {
                    let child = this.domFragment(item);
                    temp.appendChildNode(child);
                } else if (this.isElText(item)) {
                    let child = this.domFragment(item);
                    temp.appendChildNode(child);
                }
            })

            return temp;

        }
        // 编译函数
        compile(node) {
            if (!(node instanceof VNode)) {
                throw new Error('node is not VNode')
            }
            if (this.isElement(node.dom)) {
                console.log(node.dom.attributes, '=====')

                let attrs = node.dom.attributes
                // 各种语法都用一用 嘻嘻
                Array.from(attrs).forEach(attr => {
                    let attrKey = attr.name;
                    let attrVal = attr.value;
                    this.comDirective(attrKey, attrVal, node);
                });
                node.childNodes.forEach(ele => {
                    this.compile(ele);
                });
            } else {
                // 文本
                if (!node.value) return;
                node.template.forEach(temp => {
                    if (this.isInterpolation(temp)) {
                        console.log(RegExp.$1)
                        this.compileText(node);
                    }
                });
            }
        }

        // 解析指令
        comDirective(attrKey, attrVal, node) {
            if (this.isDirective(attrKey)) {
                // 如果是以 t-开头的指令
                console.log('t-开头')
                let dir = attrKey.substring(2);
                // 执行
                if (!this[dir]) new Error('directive is not define');
                this[dir](node, this.$vm, attrVal);
            }
            if (this.isEvent(attrKey)) {
                // @开头的事件绑定
                let dir = attrKey.substring(1);
                this.bindEvent(dir, attrVal, this.$vm, node);
            }
            if (this.isBind(attrKey)) {
                // :开头的 attr绑定
                let dir = attrKey.substring(1);
                this.bindValue(dir, attrVal, this.$vm, node);
            }
        }
        // 是不是t-的指令
        isDirective(attr) {
            console.log(attr)
            return attr.indexOf('t-') === 0;
        }
        // 是不是@开头的事件绑定
        isEvent(attr) {
            return attr.indexOf('@') === 0;
        }
        // 是不是:开头的数据绑定
        isBind(attr) {
            return attr.startsWith(':');
        }
        // 是不是dom节点
        isElement(node) {
            return node.nodeType === 1;
        }
        isStr(val) {
            return (val.startsWith('"') || val.startsWith("'"))
        }
        // 是不是文本节点
        isElText(node) {
            return node.nodeType === 3;
        }
        // 插值文本
        isInterpolation(node) {
            // console.log(node, '匹配')

            return /\{\{(.*)\}\}/.test(node);
        }
        // 绑定事件 嗯  这里没有匹配那种句柄写法
        bindEvent(dir, exp, vm, node) {
            let fun = vm.$options.methods && vm.$options.methods[exp];
            if (dir && fun) {
                node.dom.addEventListener(dir, fun.bind(vm), false);
            }
        }

        // 解析 : 数据绑定
        bindValue(dir, exp, vm, node) {
            if (dir === 'style') {
                this.bindStyle(exp, vm, node);
                return
            }
            let value = this.isStr(exp) ? exp.replace(/'|"/g, '') : analysisInterpolation(exp, vm.$data, vm.$data)
            node.dom.setAttribute(dir, value)
            removeAttr(node, dir, ':')
        }

        // 解析插值文本
        compileText(node) {
            this.update(node, this.$vm, RegExp.$1, 'text')
        }
        // style绑定
        bindStyle(exp, vm, node) {
            if (exp.startsWith('{')) {
                let str = exp.replace(/{|}/g, '');
                // let style = str.split(',').join(';') + ';';
                let styleArr = str.split(',');
                styleArr.forEach(prop => {
                    let tempStyle = prop.trim().split(':');
                    tempStyle[0] = hump(tempStyle[0]);
                    node.dom.style[tempStyle[0]] = tempStyle[1]
                })
            } else {
                let styleObj = analysisInterpolation(exp, vm.$data, vm.$data);
                if (typeof styleObj !== 'object') return
                Object.keys(styleObj).forEach(key => {
                    node.dom.style[key] = styleObj[key]
                })
            }
        }
        // 更新函数
        update(node, vm, exp, dir) {
            const updaterFn = this[dir + "Updater"];
            // 初始化
            let data = analysisInterpolation(exp, vm.$data, vm.$data)
            updaterFn && updaterFn.call(this, node, data);
            // 依赖收集
            new Watcher(vm, analysisInterpolation, exp, (value) => {
                updaterFn && updaterFn.call(this, node, value);
            });
        }

        textUpdater(node, value) {
            console.log('添加文本', this.$vm.$data.a)
            this.render(node, value, 'text');
        }

        modelUpdater(node, value) {
            this.render(node, value, 'model');
        }

        htmlUpdater(node, value) {
            this.render(node, value, 'html');
        }
        render(node, val, exp) {
            if (!(node instanceof VNode)) {
                throw new Error('node is not VNode')
            }
            if (this.isElement(node.dom)) {
                // 说明是t-开头的指令
                switch (exp) {
                    case 'text':
                        node.dom.innerText = val;
                        break;
                    case 'model':
                        node.dom.value = val;
                        break;
                    case 'html':
                        node.dom.innerHTML = val;
                        break;
                    case 'if':
                        node.dom.innerHTML = val;
                        break;
                    default:
                        break;
                }
            } else {
                node.dom.nodeValue = val
            }
        }
        // 解析t-text
        text(node, vm, attrval) {
            console.log('text')
            this.update(node, vm, attrval, "text");
        }
        // 解析t-model
        model(node, vm, attrval) {
            console.log('model')
            this.update(node, vm, attrval, "model");
            node.dom.addEventListener('input', e => {
                let data = analysisInterpolation(attrval, vm.$data, vm.$data);
                e.target.value = data
            })
        }

        // 解析t-html
        html(node, vm, attrval) {
            this.update(node, vm, attrval, "html");
        }

    }

    //  虚拟dom树
    class VNode {
        constructor(dom, type, value) {
            this.dom = dom;
            this.type = type;
            this.value = value;
            this.childNodes = [];
            this.template = [];
        }
        // 添加虚拟dom 节点
        appendChildNode(node) {
            if (!(node instanceof VNode)) {
                throw new Error("node is not instanceof VNode");
            }
            this.childNodes.push(node)
        }
        // 模板
        appendContentTemplate(temp) {
            this.template = temp
        }

        // 匹配{{}} 插值语法
        isInterpolation(text) {
            // 检测text 是否存在
            if (!text) return [];
            // 创建匹配的字符串列表
            let mateList = text.match(/{{[a-zA-Z_$]+[a-zA-Z0-9._\[\]$]*}}/g);

            return mateList === null ? [] : mateList;
        }

    }

    // 功能 函数 解析数据值
    function analysisInterpolation(str, obj, data) {
        let temp1 = str.indexOf('.');
        let temp2 = str.indexOf('[');
        let sign = anSign(str, temp1, temp2);
        let newStr = anNewStr(str);
        if (sign || newStr) {
            if (sign && sign.startsWith('[')) {
                newStr = newStr.replace(sign, '')
                sign = sign.replace(/\[|\]/g, '')
                if (sign && (sign.startsWith("'") || sign.startsWith('"'))) {
                    sign = sign.replace(/'|"/g, '')
                } else if (isNaN(Number(sign))) {
                    sign = analysisInterpolation(sign, data)
                }
            }
        }
        let val = obj[sign]
        if (newStr) {
            return analysisInterpolation(newStr, val)
        }
        console.log(val)
        return val
    }
    function anSign(str, temp1, temp2) {
        let temp;
        if (temp1 !== -1 && temp2 !== -1) {
            temp = temp1 < temp2 ? temp1 === 0 ? str.split('.')[1] : str.split('.')[0] : temp2 === 0 ? str.match(/\[[a-zA-Z_0-9.''""]*\]/g)[0] : str.split('[')[0];
        } else if (temp1 !== -1) {
            temp = temp1 === 0 ? str.split('.')[1] : str.split('.')[0]
        } else if (temp2 !== -1) {
            temp = temp2 === 0 ? str.match(/\[[a-zA-Z_0-9''""]*\]/g)[0] : str.split('[')[0];
        } else {
            temp = str
        }

        return temp;
    }
    function anNewStr(str) {
        if (str && str.startsWith('.')) {
            str = str.substring(1)
        }
        let temp1 = str.indexOf('.');
        let temp2 = str.indexOf('[');
        let temp;

        if (temp1 !== -1 && temp2 !== -1) {
            // console.log(str, temp1, temp2)
            temp = temp1 < temp2 ? str.substring(temp1) : str.substring(temp2);
        } else if (temp1 !== -1) {

            // console.log(str, temp1, temp2, '====')
            temp = str.substring(temp1)
        } else if (temp2 !== -1) {
            // console.log(str, temp1, temp2)
            temp = str.substring(temp2)
        } else {
            return
        }
        if (temp && temp.startsWith('.')) {
            temp = temp.substring(1)
        }
        return temp
    }
    // 删除attr
    function removeAttr(node, dir, str) {
        node.dom.removeAttribute(str + dir)
    }
    // -连接 转驼峰
    function hump(str) {
        let reg = /-(\w)/g;
        return str.replace(reg, function (a, b) {
            return b.toUpperCase();
        });
    }

    return TempVue;
});